﻿<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>GoJS Initial Viewport -- Northwoods Software</title>
  <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
  <script src="../release/go.js"></script>
  <script src="goIntro.js"></script>
</head>
<body onload="goIntro()">
<div id="container" class="container-fluid">
<div id="content">

<h1>Initial, Automatic, and Programmatic Viewport Management</h1>
<p>
Once you have created and assigned a model to cause some Parts to appear in your Diagram,
you can control where your parts initially appear in the viewport, and you can control
where they are shown after the diagram has been modified.
</p>

<h2 id="InitialViewport">Initial viewport</h2>
<p>
You can very easily set the <a>Diagram.initialPosition</a> and/or <a>Diagram.initialScale</a> properties
at any time, even before assigning the model.  This will cause the <a>Diagram.position</a> and/or <a>Diagram.scale</a>
properties to be set to the specified initial value(s) once all of the Parts have been created and any initial layout has been performed.
</p>
<p>
But what if you do not know how big your diagram document will be?
If you want to show a particular area of the document, you will not know what position to set.
If you want to show a big document at the largest scale that shows all of it, you will not know what scale to set.
</p>
<p>
One solution to this problem is to set the <a>Diagram.initialDocumentSpot</a> and <a>Diagram.initialViewportSpot</a> properties
to particular <a>Spot</a> values.
For example, if you are showing a tree-like diagram and you want tree to be centered horizontally but positioned vertically at the top,
you can do something like this when you create the Diagram:
</p>
<pre class="lang-js">
  $(go.Diagram, "myDiagramDiv",
    {
      initialDocumentSpot: go.Spot.Top,
      initialViewportSpot: go.Spot.Top
    })
</pre>
<p>
This makes sure that after the initial layout of your diagram the middle top point of the diagram contents
is positioned to be at the middle top point of the viewport.
</p>
<p>
Another solution to this problem is to set the <a>Diagram.initialContentAlignment</a> or <a>Diagram.initialAutoScale</a> properties.
For example it is fairly common to want to make sure that small documents appear top-centered within the diagram window --
just set <a>Diagram.initialContentAlignment</a> to <a>Spot,Top</a>.
Or if you want to "zoom-to-fit" the diagram, just set <a>Diagram.initialAutoScale</a> to <a>Diagram,Uniform</a>.
</p>
<pre class="lang-js">
  $(go.Diagram, "myDiagramDiv",
    {
      initialAutoScale: go.Diagram.Uniform
    })
</pre>
<p>
More generally, you may want to try to center a particular <a>Node</a>.
Here is how you can do that:
</p>
<pre class="lang-js" id="centernode">
  diagram.nodeTemplate =
    $(go.Node, "Auto",
      new go.Binding("location", "loc"),
      $(go.Shape, { fill: "lightyellow" }),
      $(go.TextBlock, { margin: 5 },
        // show the location as text in the node
        new go.Binding("text", "loc",
                       function (p) { return p.x.toFixed() + ", " + p.y.toFixed(); }))
    );

  // initialize the model with random nodes:
  var nodeDataArray = [];
  for (var i = 0; i &lt; 20; i++ ) {
    nodeDataArray.push({ loc: new go.Point(Math.random() * 600, Math.random() * 300) });
  }
  diagram.model.nodeDataArray = nodeDataArray;

  // this event handler is called when the diagram is first ready
  diagram.addDiagramListener("InitialLayoutCompleted", function(e) {
    // pick a random node data
    var data = nodeDataArray[Math.floor(Math.random()*nodeDataArray.length)];
    // find the corresponding Node
    var node = diagram.findNodeForData(data);
    // and center it and select it
    diagram.centerRect(node.actualBounds);
    diagram.select(node);
  });
</pre>
<script>goCode("centernode", 300, 150)</script>
<p>
Note: because by default one cannot scroll past any edge of the document plus any <a>Diagram.scrollMargin</a>,
if the selected node happens to be at or near an edge, the node cannot actually be centered in the viewport.
</p>

<h2 id="AutomaticViewportManagement">Automatic viewport management</h2>
<p>
There are also times when you will want to control the viewport (i.e. the <a>Diagram.position</a> and <a>Diagram.scale</a>)
after every change to the diagram.
For example, if you always want to keep the document centered after the user has moved or deleted or inserted nodes,
set <a>Diagram.contentAlignment</a> (rather than <a>Diagram.initialContentAlignment</a>) to <a>Spot.Center</a>.
</p>
<p>
Or if you always want to keep the document "zoomed-to-fit", set <a>Diagram.autoScale</a>
(rather than <a>Diagram.initialAutoScale</a>) to <a>Diagram,Uniform</a>.
As an example, the <a>Overview</a> diagram does this.
</p>

<h2 id="ProgrammaticViewportManagement">Programmatic viewport management</h2>
<p>
If you do not want continual repositioning or rescaling of the diagram, but you do sometimes want to change
the <a>Diagram.position</a> and/or the <a>Diagram.scale</a>, you can set those properties to whatever values you like.
However, please note that the ultimate value for <a>Diagram.position</a> is normally limited by the <a>Diagram.documentBounds</a>
and the size of the viewport and the scale of the diagram.
The <a>Diagram.scale</a> is limited by <a>Diagram.minScale</a> and <a>Diagram.maxScale</a>.
</p>
<p>
But it is more common to call a method on Diagram to achieve the results that you want.
For example, to get the effect of the <a>Diagram.initialDocumentSpot</a> and <a>Diagram.initialViewportSpot</a> properties
that are used when the "InitialLayoutCompleted" DiagramEvent occurs, call
<a>Diagram.alignDocument</a> with the two desired Spots that you want to have coincide.
</p>
<p>
As already demonstrated above, if you want to try to center a particular node in the viewport,
you can call <a>Diagram.centerRect</a> with the node's <a>GraphObject.actualBounds</a>.
</p>
<p>
If you want to make sure that a particular node is within the viewport, but not necessarily centered,
call <a>Diagram.scrollToRect</a>.
</p>
<p>
If you just want to scroll the diagram, in the same manners as the user might via a scrollbar or the mouse wheel,
call <a>Diagram.scroll</a> with arguments that specify how much to scroll and in which direction.
</p>

<p>
The just-mentioned Diagram methods do not change the <a>Diagram.scale</a>.
If you want to rescale the diagram so that the whole document bounds are shown, call <a>Diagram.zoomToFit</a>.
More generally, if you want a particular area of your diagram to be shown at whatever scale will make it fit in the viewport, call <a>Diagram.zoomToRect</a>.
</p>

</div>
</div>
</body>
</html>
